package org.example.spring.repository.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.example.spring.repository.mapper.DepartmentMapper;
import org.example.spring.repository.model.Department;
import org.example.spring.repository.service.IDepartmentService;
import org.example.spring.utils.TransactionUtil;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * LuoYu
 * 2022/12/12 19:48
 **/
@Service
@Slf4j
@Primary
public class DepartmentServiceImpl implements IDepartmentService {

    @Resource
    private DepartmentMapper departmentMapper;


    @Override
    public boolean create(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        int  code =  name.hashCode() % 4;
        if(code == 0) {
            log.warn("[{}]触发回滚",name);
            return false;
        }
        if(hasThrow) {
            return false;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createREQUIRED(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
    public void createSupports(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
    public void createMandatory(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void createRequiredNew(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NEVER)
    public void createNever(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
    public void createNested(String name, boolean hasThrow) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            System.out.println(2 / 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void asyncCreateRequired(String name, boolean hasThrow) {
        log.info("执行异步插入部门任务:[{}]",name);
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            log.warn("抛出异常: name:[{}]",name);
            System.out.println(2 / 0);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void manualSyncTransactionCreate(String name, boolean hasThrow, CountDownLatch count, AtomicBoolean single) {
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        if(hasThrow) {
            log.warn("抛出异常: name:[{}]",name);
            single.set(true);
        }
        count.countDown();
        try {
            // 等待其他线程结束
            count.await();
            boolean b = single.get();
            // 其他线程出现异常，回滚
            if(b) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("发生异常",e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }


    @Override
    @Async
    public void saveStatusAsyncTransactionCreate(String name, boolean hasThrow, CountDownLatch count, AtomicBoolean single, List<TransactionStatus> statusList) {
        // 获取一个具有默认传播机制的事务状态实例
        TransactionStatus transactionStatus = TransactionUtil.getTransactionStatus(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        statusList.add(transactionStatus);
        log.info("执行保存事务状态异步插入部门任务:[{}]",name);
        Department department = Department.builder().name(name).levels(0).orderNo(0).build();
        departmentMapper.insert(department);
        count.countDown();
        if(hasThrow) {
            single.set(true);
            log.warn("抛出异常: name:[{}]",name);
            System.out.println(2 / 0);
            // 表示抛出异常，需要回滚
        }
    }
}
